package instructions;

import values.Boolean;
import values.Value;
import expressions.BadExpressionException;
import expressions.Expression;
import base.AST;
import base.Environment;
import base.Interpreter;

public class While implements Instruction {

	private AST test;
	private Instruction in;

	/**
	 * Creates the instruction
	 * while (test) {
	 * 		in
	 * }
	 */
	public While(AST test, Instruction in) {
		assert test instanceof Expression || test instanceof Value;
		this.test = test;
		this.in = in;
	}

	/**
	 * If the test corresponds to the Boolean true, executes in and then creates a new While with the new environment
	 */
	public Environment instr(Environment env) throws BadInstructionException {
		Environment newEnv = env.clone();

		try {
			Boolean testBoolean = Interpreter.getBoolean(this.test, env);

			if (testBoolean.eval()) {
				/* create the next while */
				While next = new While(this.test, this.in);
				/* do the instruction inside the while */
				Environment tempEnv = in.instr(newEnv);
				/* start the next while */
				return next.instr(tempEnv);
			} else {
				/* skip the while */
				return newEnv;
			}

		} catch (BadExpressionException e) {
			throw new BadInstructionException(e,
					"Evaluation of the while loop condition does not give a boolean value");
		}

	}

}
